Skip to main content

Build the app

We're going to install the Storage app's dependencies, build the app, and then explain what Cubist does behind the scenes during the build process.

Install app dependencies

note

The following instructions assume that you have installed Cubist.

Let's start by installing the Cubist Node.js SDK and related dependencies. cd to the application directory of your chosen example and language. Then:

npm install

Build instructions

In the cubist-config.json we specify the target chains on which each contract should run:

{
...
"targets": {
"ethereum" : {
"files": ["./contracts/StorageReceiver.sol"]
},
"polygon": {
"files": ["./contracts/StorageSender.sol"]
}
},
...
}

To change chains, simply alter the configuration file to specify a different chain.

note

Cubist only allows you to assign chains at a per file granularity---not per contract. If you have two contracts in the same file and want to deploy them on different chains, you'll have to put each contract in its own file.

Now that we've specified where our contracts should run, we build the project using Cubist:

cubist build

What's going on behind the scenes

When you invoke build, Cubist generates new files in the build directory, organized with one directory per target chain:

build
├── ethereum
│   ├── artifacts // Compiled contracts that will run on ethereum
│ │ ├── ...
│   └── contracts // Source files of original and shim contracts on ethereum
| └── ...
├── orm
│   └── index.js/.ts // ORM interface we'll use in the app to interface with contracts
└── polygon
├── artifacts // Compiled contracts that will run on polygon
│   ├── StorageReceiver.sol
│   │   └── StorageReceiver.json // ABI (and more) for the shim StorageReceiver contract
│   └── StorageSender.sol
│   └── StorageSender.json // ABI (and more) for the "normal" StorageSender contract
└── contracts
├── StorageReceiver.bridge.json // Configuration for the Cubist relayer
├── StorageReceiver.sol // Shim contract source
└── StorageSender.sol // Original StorageSender source

Within each target directory---here, the polygon and ethereum directories---Cubist saves:

  1. the ABIs produced when compiling the contracts with solc (within the artifacts directory)
  2. the original and shim source files (in the contracts directory).

In this example, the interesting files are in the polygon directory. That's because the StorageSender contract, deployed on Polygon, makes a cross-chain call by executing receiver.store(..) on a StorageReceiver contract deployed on Ethereum. As a result, Cubist must generate a StorageReceiver shim on Polygon for the the StorageSender contract to interact with; that shim will emit events anytime StorageSender calls a StorageReceiver function, and the off-chain Cubist relayer will relay those events to the real StorageReceiver contract on Ethereum. Here's an example of the generated shim code, which lives in build/polygon/contracts/StorageReceiver.sol:

contract StorageReceiver {

event __cubist_event_StorageReceiver_store(uint256 num);

...

function store(uint256 num) public onlyCaller {
emit __cubist_event_StorageReceiver_store(num);
}

}

The build also generates the information that lets the off-chain relayer do its job; this information is in the StorageReceiver.bridge.json file.

danger

You should not modify any of the files in the build directory. These files are automatically generated, so your changes may get overwritten.

The build/orm directory

Finally, the orm directory contains Cubist-generated bindings to our smart contracts. We'll use the bindings to interface with our contracts from JavaScript in the next section.